package com.gitee.wsl.doc.prosemirror.transform.step

import com.gitee.wsl.doc.prosemirror.exception.RangeError
import com.gitee.wsl.doc.prosemirror.model.Schema
import com.gitee.wsl.doc.prosemirror.model.node.Node
import com.gitee.wsl.doc.prosemirror.transform.map.Mappable
import com.gitee.wsl.doc.prosemirror.transform.map.StepMap
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.put

// Update an attribute in the doc node.
class DocAttrStep(
    // The attribute to set.
    val attr: String,
    // The attribute's new value.
    val value: Any?
) : Step() {
    override val from: Int
        get() = 0
    override val to: Int
        get() = 0

    override fun apply(doc: Node): StepResult {
        val attrs = doc.attrs.toMutableMap()
        attrs[attr] = value
        val updated = doc.type.create(attrs, doc.content, doc.marks)
        return StepResult.Companion.ok(updated)
    }

    override fun getMap() = StepMap.Companion.empty

    override fun invert(doc: Node): Step {
        return DocAttrStep(attr, doc.attrs[attr])
    }

    override fun map(mapping: Mappable): Step {
        return this
    }

    override fun toJSON() = buildJsonObject {
        put("stepType", "docAttr")
        put("attr", attr)
        put("value", value)
    }

    companion object : StepJsonParser<DocAttrStep> {
        init {
            jsonID("docAttr", this)
        }

        override fun fromJSON(schema: Schema, json: JsonObject): DocAttrStep {
            val attr = json["attr"]?.jsonPrimitive?.contentOrNull
                ?: throw RangeError("Invalid input for DocAttrStep.fromJSON")
            val value = json["value"]?.jsonPrimitive?.anyOrNull()
            return DocAttrStep(attr, value)
        }
    }
}

fun Step.Companion.docAttr(
    // The attribute to set.
     attr: String,
    // The attribute's new value.
     value: Any?
) = DocAttrStep(attr,value)